using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.Logic;
using NetProtocol.Client;
using NetProtocol.Enum;
using NetProtocol.POD;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.GamePlay
{
    public class CLevelLogicModule : Singleton<CLevelLogicModule>, CNetLevelLogic
    {
        private CLevelLogicModule()
        {
        }

        public static CNetLevelLogic NetCore => Instance;


        private bool m_IsLocal = false;

        public bool IsLocal => m_IsLocal;

        ISession CNetLevelLogic.GetSession()
        {
            if (m_IsLocal)
            {
                return LocalLogicManager.Instance.localLogicClientSession;
            }

            return LogicServerModule.Instance.CurrSession;
        }

        public void InitLocalLevel(CreateLevelPOD levelPOD, LevelSavePOD levelSavePOD, LogicPlayerPOD playerPOD)
        {
            if (!levelPOD.isLocal)
            {
                throw new ArgumentException();
            }

            m_IsLocal = true;
            LocalLogicManager.Instance.Init(playerPOD);

            // 初始化玩法数据
            LogicPlayer logicPlayer = LocalLogicManager.Instance.logicPlayer;
            GameEnterLevelPOD enterLevelPod = playerPOD.enterLevelPOD;
            logicPlayer.playData.reason = ConnectLogicReason.TryEnterLevel;
            logicPlayer.playData.levelId = enterLevelPod.levelId;
            logicPlayer.playData.levelCid = enterLevelPod.levelCid;
            logicPlayer.playData.regionCid = enterLevelPod.regionCid;
            logicPlayer.playData.portalId = enterLevelPod.portalId;
            logicPlayer.playData.clientTime = enterLevelPod.clientTime;

            SLevelLogicModule.Instance.CreateLevel(levelPOD, levelSavePOD);
            SLevelLogicModule.Instance.OnPlayerConnect(logicPlayer, levelPOD.id);
        }

        // 表现层不需要关注逻辑层的生命周期
        public void ShutdownLocalLevel()
        {
            if (!m_IsLocal)
            {
                return;
            }

            m_IsLocal = false;

            Level level = SLevelLogicModule.Instance.GetLocalLevel();
            if (level != null)
            {
                foreach (LevelPlayer player in new List<LevelPlayer>(level.players))
                {
                    SLevelLogicModule.Instance.KickPlayerOut(player.id);
                }

                SLevelLogicModule.Instance.ShutdownLevel(level.id);
            }

            LogicHelper.Router = NullProtocolRouter.Inst;
            LogicHelper.OnPlayerEnterLevel = null;
            LogicHelper.SaveLevel = null;
            LogicHelper.OnPlayerLeaveLevel = null;
        }

        void CNetLevelLogic.SC_NotifyLeave(ISession session, int outRegionCid, int outPortalMcid, int anotherLevelCid)
        {
            session.Close(true); //提前主动关闭session, 防止出现网络断线的弹框
            if (anotherLevelCid > 0)
            {
                GameScenePlayUtil.EnterLevelAfterLeftPreviousLevel(anotherLevelCid, outRegionCid, outPortalMcid);
            }
            else
            {
                var data = outRegionCid == 0 && outPortalMcid == 0 ? null : new EnterMainCityData()
                {
                    regionCid = outRegionCid,
                    portalMcid = outPortalMcid
                };
                GameplayAreaManager.Instance.Switch(GameplayAreaType.MainCity, data);
            }
        }

        void CNetLevelLogic.SC_NotifyEnterRegion(ISession session, LevelRegionPOD region)
        {
            MsgDispatcher.Broadcast<LevelRegionPOD>(MsgEventType.Level_EnterRegion, region);
        }

        void CNetLevelLogic.SC_NotifySyncPosition(ISession session, LevelMoveReason reason, int entityId,
            LevelEntityType entityType, float x, float y, float z, float speedRatio, byte dirType)
        {
            MsgDispatcher
                .Broadcast<LevelMoveReason, int, LevelEntityType, float, float, float, float, EntityMoveDirType>(
                    MsgEventType.Level_SyncEntityPos, reason, entityId, entityType, x, y, z, speedRatio,
                    (EntityMoveDirType)dirType);
        }

        void CNetLevelLogic.SC_UpdateEntities(ISession session, List<LevelEntityPOD> modifiedList,
            List<int> removedList, bool isPlayDieWhenRemove)
        {
            MsgDispatcher.Broadcast<List<LevelEntityPOD>, List<int>, bool>(MsgEventType.Level_UpdateEntities, modifiedList,
                removedList, isPlayDieWhenRemove);

            //回收POD，该POD可回收：LevelEntityPOD.DynamicFactory = PODPool<LevelEntityPOD>.Init(10);
            if (modifiedList != null)
            {
                foreach (var entityPOD in modifiedList)
                {
                    PODPool<LevelEntityPOD>.Put(entityPOD);
                }
                modifiedList.Clear();
            }
        }

        void CNetLevelLogic.SC_NotifyShowSpeechBubble(ISession session, int entityId, int bubbleGroupId,
            List<int> validBubbleIds)
        {
            MsgDispatcher.Broadcast<int, int, List<int>>(MsgEventType.Level_ShowBubble, entityId, bubbleGroupId,
                validBubbleIds);
        }

        void CNetLevelLogic.SC_UpdateEntityActivation(ISession session, List<int> entityIdList, bool isActive,
            int animActionId, bool isSetRotation, int rotationY)
        {
            LogGame.LogError("该接口暂时屏蔽，详情参考方法注释：LevelPlayEntityCtrl_MsgListener.RecvEntityActivation");
            //MsgDispatcher.Broadcast<List<int>, bool, int, bool, int>(MsgEventType.Level_EntityActive, entityIdList, isActive, animActionId, isSetRotation, rotationY);
        }

        void CNetLevelLogic.SC_NotifyActivateElevator(ISession session, int elevatorEntityId, int targetFloor,
            bool isRidingMode, bool isMoveState)
        {
            MsgDispatcher.Broadcast<int, int, bool, bool>(MsgEventType.Level_ElevatorMoveOrStop, elevatorEntityId,
                targetFloor, isRidingMode, isMoveState);
        }

        void CNetLevelLogic.SC_NotifyStartCameraMotion(ISession session, int levelScreenSwitchCid)
        {
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_NotifyStartCameraMotion, levelScreenSwitchCid);
        }

        void CNetLevelLogic.SC_NotifyEntityObstacleChange(ISession session, List<int> entityIdList,
            bool isObstacleActive)
        {
            MsgDispatcher.Broadcast<List<int>, bool>(MsgEventType.Level_NotifyEntityObstacleChange, entityIdList,
                isObstacleActive);
        }

        void CNetLevelLogic.SC_NotifyPlayEntityAnimAction(ISession session, List<int> entityIds, int actionId)
        {
            MsgDispatcher.Broadcast<List<int>, int>(MsgEventType.Level_NotifyPlayEntityAnimAction, entityIds, actionId);
        }

        void CNetLevelLogic.SC_NotifyLevelTimeShowChange(ISession session, int timeHour)
        {
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_NotifyLevelTimeShowChange, timeHour);
        }

        void CNetLevelLogic.SC_NotifyChangeSceneEffect(ISession session, int entityId, int sceneEffectId, bool isAdd)
        {
            MsgDispatcher.Broadcast<int, int, bool>(MsgEventType.Level_NotifyChangeAreaEffectGroup, entityId,
                sceneEffectId, isAdd);
        }

        void CNetLevelLogic.SC_UpdateEntityRotationY(ISession session, int entityId, LevelEntityType entityType,
            int rotationY)
        {
            MsgDispatcher.Broadcast<int, LevelEntityType, int>(MsgEventType.Level_UpdateEntityRotationY, entityId,
                entityType, rotationY);
        }

        void CNetLevelLogic.SC_NotifyActiveCheckPoint(ISession session, int entityId, bool isActive)
        {
            MsgDispatcher.Broadcast<int, bool>(MsgEventType.Level_NotifyActiveCheckPoint, entityId, isActive);
        }

        void CNetLevelLogic.SC_NotifyBuffChange(ISession session, List<LevelBuffChangePOD> changes)
        {
            MsgDispatcher.Broadcast<List<LevelBuffChangePOD>>(MsgEventType.Level_NotifyBuffChange, changes);
            foreach (var buffChangePOD in changes)
            {
                PODPool<LevelBuffChangePOD>.Put(buffChangePOD);
            }
            changes.Clear();
        }

        void CNetLevelLogic.SC_NotifyCustomBgmChange(ISession session, int bgmAudioCid)
        {
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_NotifyCustomBgmChange, bgmAudioCid);
        }

        void CNetLevelLogic.SC_NotifyStartStoryDialog(ISession session, int cid, int jumpCid, int interactingEntityId)
        {
            var entity = interactingEntityId == 0 ? null : GameplayAreaManager.Instance.curSceneArea.GetEntityById(interactingEntityId);
            StoryManager.Instance.StartPlayStoryById(cid, jumpCid, entity).Forget();
        }

        void CNetLevelLogic.SC_NotifyEnter(ISession session, EnterLevelPOD level)
        {
            MsgDispatcher.Broadcast<EnterLevelPOD>(MsgEventType.Level_Enter, level);
        }

        void CNetLevelLogic.SC_NotifyStart(ISession session)
        {
            LevelPlayModule.Instance.levelPlay.OnLevelPlayStart();
        }

        void CNetLevelLogic.SC_NotifyChangeLevelParam(ISession session, int key, int value)
        {
            MsgDispatcher.Broadcast<int, int>(MsgEventType.Level_NotifyLevelParamChange, key, value);
        }

        void CNetLevelLogic.SC_NotifyHeroFollowerChange(ISession session, int id)
        {
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_NotifyHeroFollowerChange, id);
        }

        void CNetLevelLogic.SC_NotifyChangePlayerCamera(ISession session, int cameraCid)
        {
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_NotifyChangePlayerCamera, cameraCid);
        }

        void CNetLevelLogic.SC_NotifyChangeWeather(ISession session, int id, int weatherType)
        {
            MsgDispatcher.Broadcast<int, int>(MsgEventType.Level_NotifyChangeWeather, id, weatherType);
        }

        void CNetLevelLogic.SC_UpdateEntityAlert(ISession session, int entityId, int targetEntityId, int alertValue)
        {
            MsgDispatcher.Broadcast<int, int, int>(MsgEventType.Level_UpdateEntityAlert, entityId, targetEntityId,
                alertValue);
        }

        void CNetLevelLogic.SC_UpdateHeroCarrier(ISession session, int heroEntityId, int entityId, bool isRemoved)
        {
            MsgDispatcher.Broadcast<int, int, bool>(MsgEventType.Level_UpdateCarrier, heroEntityId, entityId,
                isRemoved);
        }

        void CNetLevelLogic.SC_NotifyLeaderHeroChanged(ISession session, int heroEntityId, LevelHeroPOD leaderHeroPOD)
        {
            MsgDispatcher.Broadcast<int, LevelHeroPOD>(MsgEventType.Level_LeaderChanged, heroEntityId, leaderHeroPOD);
        }

        void CNetLevelLogic.SC_NotifyStartItemSubmit(ISession session, int itemSubmitCid)
        {
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_StartItemSubmit, itemSubmitCid);
        }

        void CNetLevelLogic.SC_NotifyBattleSettlement(ISession session, BattleSettlementPOD settlementPOD)
        {
            //同步数据以后再派发事件，好统一处理逻辑
            LevelPlayModule.Instance.levelPlay.UpdateBattleSettlementInfo(settlementPOD);
            MsgDispatcher.Broadcast(MsgEventType.Level_BattleSettlement);
        }

        void CNetLevelLogic.SC_NotifyDrop(ISession session, int srcEntityId, List<ItemShowPOD> items)
        {
            if (srcEntityId != 0)
            {
                LevelPlayModule.Instance.levelPlay?.regionCtrl.entityCtrl.ShowEntityDrop(srcEntityId, items).Forget();
            }
            if (items != null)
            {
                foreach (var item in items)
                {
                    PODPool<ItemShowPOD>.Put(item);
                }
                items.Clear();
            }
        }

        /// <summary>
        /// 清理单个hero的buff
        /// </summary>
        /// <param name="session"></param>
        /// <param name="playerId"></param>
        /// <param name="heroId"></param>
        void CNetLevelLogic.SC_NotifyClearHeroBuff(ISession session, long playerId, long heroId)
        {
            LevelPlayModule.Instance.levelPlay?.ClearHeroBuff(playerId, heroId);
        }

        /// <summary>
        /// 团灭
        /// </summary>
        /// <param name="session"></param>
        /// <param name="playerId"></param>
        /// <param name="leaderHeroId"></param>
        void CNetLevelLogic.SC_NotifyTeamWipe(ISession session, long playerId, long leaderHeroId)
        {
            LevelPlayModule.Instance.levelPlay?.regionCtrl.OnTeamWipe(playerId, leaderHeroId);
        }

        /// <summary>
        /// 同步英雄战斗属性
        /// </summary>
        /// <param name="session"></param>
        /// <param name="pid"></param>
        /// <param name="heroAttrs"></param>
        void CNetLevelLogic.SC_NotifyHeroesAttr(ISession session, long pid, List<LevelHeroAttrSyncPOD> heroAttrs, AttrChangeReason reason)
        {
            LevelPlayModule.Instance.levelPlay?.SyncHeroAttr(pid, heroAttrs, reason);
            foreach (var pod in heroAttrs)
            {
                PODPool<LevelHeroAttrSyncPOD>.Put(pod);
            }
            heroAttrs.Clear();
        }

        void CNetLevelLogic.SC_NotifyPlayOrStopEntityEffect(ISession session, int singleEntityId,
            List<int> multiEntityIds, int effectResCid, int bindPointCid, bool isAdd)
        {
            MsgDispatcher.Broadcast<int, List<int>, int, int, bool>(MsgEventType.Level_NotifyChangeBindEffect,
                singleEntityId, multiEntityIds, effectResCid, bindPointCid, isAdd);
        }

        void CNetLevelLogic.SC_NotifyRevive(ISession session, long pid)
        {
            LevelPlayModule.Instance.levelPlay?.RevivePlayer(pid);
        }

        void CNetLevelLogic.SC_NotifyPushEntity(ISession session, int entityId, int maxDistance)
        {
            MsgDispatcher.Broadcast<int, int>(MsgEventType.Level_PushEntity, entityId, maxDistance);
        }

        void CNetLevelLogic.SC_NotifyStartMiniGame(ISession session, LevelMiniGameType type, int miniGameCid)
        {
            MsgDispatcher.Broadcast<LevelMiniGameType, int>(MsgEventType.Level_StartMiniGame, type, miniGameCid);
        }

        void CNetLevelLogic.SC_NotifyChangeEntityAudio(ISession session, int entityId, int audioCid)
        {
            MsgDispatcher.Broadcast<int, int>(MsgEventType.Level_ChangeEntityAudio, entityId, audioCid);
        }
    }
}